//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_REFLECTION_REFLECTION_HPP
#define RS_REFLECTION_REFLECTION_HPP

#include "rs/reflection/Attribute.hpp"
#include "rs/reflection/AttributeProperties.hpp"
#include "rs/reflection/Class.hpp"
#include "rs/reflection/ClassBuilder.hpp"
#include "rs/reflection/Method.hpp"
#include "rs/reflection/ReflectionCenter.hpp"
#include "rs/reflection/Types.hpp"
#include "rs/Assert.hpp"

namespace rs
{
    namespace reflection
    {
        namespace hidden
        {
            template< typename TClassBuilderVisitor >
            class ClassBuilderHidder
            {
            public:
                
                ClassBuilderHidder(ClassBuilder< TClassBuilderVisitor >* cb)
                : cb_(cb) {
                }
                
                ~ClassBuilderHidder() {
                    delete cb_;
                }
                
                ClassBuilder< TClassBuilderVisitor > GetClassBuilder() {
                    return *cb_;
                }
                
            private:
                
                ClassBuilder< TClassBuilderVisitor >* cb_;
            };
        }
    }
}

#define RS_DECLARE_REFLECTION() \
    public: \
        static rs::reflection::Class const ClassRecord; \
        rs::reflection::Class const& GetClassRecord() const;
        
#define RS_DECLARE_POLYMORPHIC_REFLECTION() \
    public: \
        static rs::reflection::Class const ClassRecord; \
        virtual rs::reflection::Class const& GetClassRecord() const;
        
#define RS_DEFINE_CLASSRECORDGETTER(type) \
    rs::reflection::Class const& type::GetClassRecord() const {\
        return type::ClassRecord; \
    }
       
     
#define RS_DEFINE_REFLECTION_CLASS(type) \
    RS_DEFINE_CLASSRECORDGETTER(type) \
    rs::reflection::Class const type::ClassRecord = rs::reflection::ClassBuilder< rs::reflection::NullClassVisitor >(#type).BindDestructor< type >()
    
#define RS_DEFINE_REFLECTION_SUBCLASS(type, parentType) \
    RS_DEFINE_CLASSRECORDGETTER(type) \
    rs::reflection::Class const type::ClassRecord = rs::reflection::ClassBuilder< rs::reflection::NullClassVisitor >(#type, &parentType::ClassRecord).BindDestructor< type >()
        
#define RS_DEFINE_REFLECTION_TEMPLATED_CLASS(templateSig, type) \
    templateSig \
    RS_DEFINE_CLASSRECORDGETTER(type); \
    templateSig \
    RS_DEFINE_REFLECTION_CLASS(type)
    
#define RS_DEFINE_REFLECTION_TEMPLATED_SUBCLASS(templateSig, type, parentType) \
    templateSig \
    RS_DEFINE_CLASSRECORDGETTER(type); \
    templateSig \
    RS_DEFINE_REFLECTION_CLASS(type, parentType)


namespace rs
{
    namespace reflection
    {
        template< typename T >
        inline Char8 const* TypeId(T const& obj) {
            return obj.GetClassRecord().GetName();
        }
        
        template< typename TLeft, typename TRight >
        inline TLeft SafeCast(TRight const* o) {
            typedef typename meta::RemoveConstVolatile< typename meta::RemovePointer< TRight >::Result >::Result CastType;
            if (o && o->GetClassRecord().IsSubclass(CastType::ClassRecord)) {
                return static_cast< TLeft >(o);
            }
            
            return 0;
        }
                
        template< typename TLeft, typename TRight >
        inline TLeft SafeCast(TRight* o) {
            typedef typename meta::RemoveConstVolatile< typename meta::RemovePointer< TRight >::Result >::Result CastType;
            if (o && o->GetClassRecord().IsSubclass(CastType::ClassRecord)) {
                return static_cast< TLeft >(o);
            }
            
            return 0;
        }
        
        template< typename TLeft, typename TRight >
        inline TLeft UnsafeCast(TRight const* o) {
            typedef typename meta::RemoveConstVolatile< typename meta::RemovePointer< TRight >::Result >::Result CastType;
            RS_ASSERTF(o && o->GetClassRecord().IsSubclass(CastType::ClassRecord), "object is not a subclass of %s", CastType::ClassRecord.GetName());
            return static_cast< TLeft >(o);
        }
        
        template< typename TLeft, typename TRight >
        inline TLeft UnsafeCast(TRight* o) {
            typedef typename meta::RemoveConstVolatile< typename meta::RemovePointer< TRight >::Result >::Result CastType;
            RS_ASSERTF(o && o->GetClassRecord().IsSubclass(CastType::ClassRecord), "object is not a subclass of %s", CastType::ClassRecord.GetName());
            return static_cast< TLeft >(o);            
        }
    }
}

#endif // RS_REFLECTION_REFLECTION_HPP
